/**
 * Copyright (c) 2024-2025 National Fundamental Software of China Co., Ltd.
 *
 * You should have find a copy of NFSChina License. If not, please contact us
 * by email <os_support@nfschina>
 *
**/

/*
    SPDX-FileCopyrightText: 2011 Martin Gräßlin <mgraesslin@kde.org>
    SPDX-FileCopyrightText: 2012 Gregor Taetzner <gregor@freenet.de>
    SPDX-FileCopyrightText: 2015-2018 Eike Hein <hein@kde.org>
    SPDX-FileCopyrightText: 2021 Mikel Johnson <mikel5764@gmail.com>
    SPDX-FileCopyrightText: 2021 Noah Davis <noahadvs@gmail.com>

    SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQml 2.15
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.components 2.0 as PC2
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami 2.16 as Kirigami

// ScrollView makes it difficult to control implicit size using the contentItem.
// Using EmptyPage instead.
EmptyPage {
    id: root
    property alias model: view.model
    property alias count: view.count
    property alias currentIndex: view.currentIndex
    property alias currentItem: view.currentItem
    property alias delegate: view.delegate
    property alias section: view.section
    property alias view: view

    property int itemLeftSpace: 18 * scaleFactor
    property int itemRightSpace: itemLeftSpace
    property int paddingValue: 12 * scaleFactor
    property bool mainContentView: false
    property bool hasSectionView: false
    property bool isCategoryList: false
    property real scaleFactor: PlasmaCore.Units.devicePixelRatio

    signal showSectionViewRequested(string sectionName)

    clip: view.height < view.contentHeight
    header: MouseArea {
        visible: false
        implicitHeight: KickoffSingleton.listItemMetrics.margins.top
        hoverEnabled: true
        onEntered: {
            if (containsMouse) {
                let targetIndex = view.indexAt(mouseX + view.contentX, view.contentY)
                if (targetIndex >= 0) {
                    view.currentIndex = targetIndex
                    view.forceActiveFocus(Qt.MouseFocusReason)
                }
            }
        }
    }

    leftPadding: isCategoryList ? 0 : paddingValue
    rightPadding: isCategoryList ? 0 : paddingValue
    implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
                            contentWidth, // exclude padding to avoid scrollbars automatically affecting implicitWidth
                            )

    contentItem: ListView {
        id: view

        readonly property real availableWidth: width - leftMargin - rightMargin
        readonly property real availableHeight: height - topMargin - bottomMargin
        property bool movedWithKeyboard: false

        spacing: 0
        Accessible.role: Accessible.List
        snapMode: ListView.NoSnap
        flickDeceleration: flickDeceleration * 6
        implicitWidth: contentWidth + leftMargin + rightMargin
        implicitHeight: {
            // use grid cells to determine size
            let h = KickoffSingleton.gridCellSize * plasmoid.rootItem.minimumGridRowCount
            // If no grids are used, use the number of items that would fit in the grid height
            if (plasmoid.configuration.favoritesDisplay !== 0 && plasmoid.configuration.applicationsDisplay !== 0) {
                h = Math.floor(h / plasmoid.rootItem.listDelegateHeight) * plasmoid.rootItem.listDelegateHeight
            }
            return h + topMargin + bottomMargin
        }

        leftMargin: 0
        rightMargin: 0

        currentIndex: -1
        focus: true
        interactive: true //height < contentHeight
        boundsBehavior: Flickable.StopAtBounds

        Component {
            id: highlight
            Rectangle {
                width: view.cellWidth; height: view.cellHeight
                color: "#0E0F0F"; radius: 8 * scaleFactor
                opacity: 0.1
            }
        }

        // This is actually needed. The highlight will animate from thin to wide otherwise.
        highlightResizeDuration: 0
        highlightMoveDuration: 0
        highlight: highlight

        delegate: KickoffListDelegate {
            width: view.availableWidth
            height: Math.ceil((isCategoryList ? 48 : 42) * scaleFactor)
            leftPadding: itemLeftSpace
            isCategoryConent: isCategoryList
        }
        
        section {
            property: "group"
            criteria: ViewSection.FullString
            delegate: Rectangle {
                width: view.availableWidth
                height: Math.ceil(42 * scaleFactor)
                color: "transparent"
                PC3.Label {
                    id: contentLabel
                    anchors.left: parent.left
                    width: section.length === 1
                           ? KickoffSingleton.compactListDelegateContentHeight + leftPadding + rightPadding
                           : parent.width
                    height: parent.height
                    leftPadding: itemLeftSpace
                    horizontalAlignment: section.length === 1 ? Text.AlignHCenter : Text.AlignLeft
                    verticalAlignment: Text.AlignVCenter
                    maximumLineCount: 1
                    elide: Text.ElideRight
                    color: PlasmaCore.ColorScope.textColor
                    //font.pixelSize: KickoffSingleton.compactListDelegateContentHeight
                    enabled: true
                    text: section.length === 1 ? section.toUpperCase() : section
                    textFormat: Text.PlainText
                }
                MouseArea {
                    anchors.fill: parent
                    hoverEnabled: true
                    onEntered: {
                        view.currentIndex = -1
                        contentLabel.color = "#A8A8A8"
                    }
                    onExited: {
                        contentLabel.color = PlasmaCore.ColorScope.textColor
                    }
                    onClicked: {
                        root.showSectionViewRequested(contentLabel.text)
                    }
                }
            }
        }

        move: normalTransition
        moveDisplaced: normalTransition

        Transition {
            id: normalTransition
            NumberAnimation {
                duration: PlasmaCore.Units.shortDuration
                properties: "x, y"
                easing.type: Easing.OutCubic
            }
        }

        PC3.ScrollBar.vertical: NfsScrollBar {
            id: verticalScrollBar
            parent: root

            visible: false
            z: 10
            height: root.height
            implicitWidth: 2 * scaleFactor
            anchors.right: parent.right
            anchors.rightMargin: 4 * scaleFactor

            ColorAnimation {
                from: "white"
                to: "#999999"
                duration: 500
            }

            onActiveChanged: {
                visible = active
            }
        }

        Connections {
            target: plasmoid
            function onExpandedChanged() {
                if (plasmoid.expanded) {
                    view.currentIndex = -1
                    view.positionViewAtBeginning()
                }
            }
        }

        Timer {
            id: movedWithKeyboardTimer
            interval: 200
            onTriggered: view.movedWithKeyboard = false
        }

        function focusCurrentItem(event, focusReason) {
            currentItem.forceActiveFocus(focusReason)
            event.accepted = true
        }

        Keys.onMenuPressed: if (currentItem !== null) {
                                currentItem.forceActiveFocus(Qt.ShortcutFocusReason)
                                currentItem.openActionMenu()
                            }
        Keys.onPressed: {
            let targetX = currentItem ? currentItem.x : contentX
            let targetY = currentItem ? currentItem.y : contentY
            let targetIndex = currentIndex
            let atFirst = currentIndex === 0
            let atLast = currentIndex === count - 1
            if (count > 1) {
                switch (event.key) {
                case Qt.Key_Up: if (!atFirst) {
                        decrementCurrentIndex()

                        if (currentItem.isSeparator) {
                            decrementCurrentIndex()
                        }

                        focusCurrentItem(event, Qt.BacktabFocusReason)
                    } break
                case Qt.Key_K: if (!atFirst && event.modifiers & Qt.ControlModifier) {
                        decrementCurrentIndex()
                        focusCurrentItem(event, Qt.BacktabFocusReason)
                    } break
                case Qt.Key_Down: if (!atLast) {
                        incrementCurrentIndex()

                        if (currentItem.isSeparator) {
                            incrementCurrentIndex()
                        }

                        focusCurrentItem(event, Qt.TabFocusReason)
                    } break
                case Qt.Key_J: if (!atLast && event.modifiers & Qt.ControlModifier) {
                        incrementCurrentIndex()
                        focusCurrentItem(event, Qt.TabFocusReason)
                    } break
                case Qt.Key_Home: if (!atFirst) {
                        currentIndex = 0
                        focusCurrentItem(event, Qt.BacktabFocusReason)
                    } break
                case Qt.Key_End: if (!atLast) {
                        currentIndex = count - 1
                        focusCurrentItem(event, Qt.TabFocusReason)
                    } break
                case Qt.Key_PageUp: if (!atFirst) {
                        targetY = targetY - height + 1
                        targetIndex = indexAt(targetX, targetY)
                        // TODO: Find a more efficient, but accurate way to do this
                        while (targetIndex === -1) {
                            targetY += 1
                            targetIndex = indexAt(targetX, targetY)
                        }
                        currentIndex = Math.max(targetIndex, 0)
                        focusCurrentItem(event, Qt.BacktabFocusReason)
                    } break
                case Qt.Key_PageDown: if (!atLast) {
                        targetY = targetY + height - 1
                        targetIndex = indexAt(targetX, targetY)
                        // TODO: Find a more efficient, but accurate way to do this
                        while (targetIndex === -1) {
                            targetY -= 1
                            targetIndex = indexAt(targetX, targetY)
                        }
                        currentIndex = Math.min(targetIndex, count - 1)
                        focusCurrentItem(event, Qt.TabFocusReason)
                    } break
                }
            }
            movedWithKeyboard = event.accepted
            if (movedWithKeyboard) {
                movedWithKeyboardTimer.restart()
            }
        }
    }
}
